
#include <assert.h>
#include <grouptreeitem.h>
#include <stdio.h>

Category::Category()
  : QObject ()
{
}

Category::Category (const QString &name)
  : QObject ()
{
  if (name.length() > 0)
    {
      _names = name.split(".", QString::SkipEmptyParts);
    }
  else
    {
      _names.clear();
    }
}


Category::Category (const Category& base)
  : QObject ()
{
  _names.clear();
  if (base._names.size() > 0)
    {
      _names << base._names;
    }
}

Category::Category (const Category& base, const QString &name)
  : QObject ()
{
  _names.clear();
  if (base._names.size() > 0)
    {
      _names << base._names;
    }

  QStringList names = name.split(".", QString::SkipEmptyParts);
  if (names.size())
    {
      _names << names;
    }

}

void Category::Clear()
{
  _names.clear();
  emit Changed();
}

int Category::GetNumberOfStages() const
{
  return _names.size();
}

const QString& Category::GetBaseName() const
{
  assert (_names.size ());

  return _names[0];
}

const QString& Category::GetHeadName() const
{
  assert (_names.size ());

  return _names[_names.size()-1];
}

const QString& Category::GetStageName(int idx) const
{
  return _names[idx];
}

QString Category::GetFullName() const
{
  return _names.join(".");
}

QString Category::GetExportName() const
{
  return _names.join(".");
}

void Category::SetFullName(const QString &name)
{
  _names = name.split(".", QString::SkipEmptyParts);

  emit Changed ();
}

void Category::PopFront()
{
  _names.pop_front();
}

void Category::RenameHead(const QString &name)
{
  if (_names.size() != 0)
    {
      _names[_names.size()-1] = name;
    }
}

bool Category::FreeRename(const Category &from, const Category &to)
{
  if (from._names.size() > _names.size())
    {
      // the origin category is greater than
      // this one so we could never be in the same category;
      return false;
    }

  unsigned num = from._names.size ();
  bool changed = false;
  bool match = true;
  for (int i=0; i<num; i++)
    {
      if (_names[i] != from._names[i])
        {
          match = false;
          break;
        }
    }
  if (!match)
    {
      return false;
    }

  // create a new list of names
  QStringList names;
  names.clear();

  // add the replacements
  int rNum = to._names.size();
  for (int i=0; i<rNum; i++)
    {
      names.append(to._names[i]);
    }
  // now add all the names that were in the old list
  for (int i=num; i<_names.size(); i++)
    {
      names.append(_names[i]);
    }
  _names = names;

  if (changed)
    {
      emit Changed();
    }
  return true;
}

bool Category::Rename(const Category &from, const Category &to)
{
  if (from._names.size() != to._names.size())
    {
      return false;
    }
  unsigned num = from._names.size () < _names.size()
                 ? from._names.size()
                 : _names.size();
  bool changed = false;
  for (int i=0; i<num; i++)
    {
      if (_names[i] != from._names[i])
        {
          break;
        }
      if (_names[i] != to._names[i])
        {
          _names[i] = to._names[i];
          changed = true;
        }
    }

  if (changed)
    {
      emit Changed();
    }
  return changed;
}


bool Category::Remove(const Category &item)
{
  if (_names.size() < item._names.size())
    {
      // This group is smaller than the given one, so it cannot reside beyond the given item
      return false;
    }
  for (int i=0; i<item._names.size(); i++)
    {
      if (_names[i] != item._names[i])
        {
          return false;
        }
    }

  // copy the names
  _names = item._names;
  _names.pop_back();

  emit Changed();

  return true;
}

void Category::Add(const QString &name)
{
  if (name.length() == 0)
    {
      return;
    }

  _names << name.split(".");
  emit Changed();
}

Category& Category::operator <<(const QString& name)
{
  _names << name;
  emit Changed();
  return *this;
}

Category& Category::operator = (const Category& item)
{
  _names = item._names;
  emit Changed ();
  return *this;
}

bool Category::operator ==(const Category& other)
{
  if (_names.size() != other._names.size ())
    {
      return false;
    }
  for (int i=0; i<_names.size (); i++)
    {
      if (_names[i] != other._names[i])
        {
          return false;
        }
    }

  return true;
}

bool Category::operator !=(const Category& other)
{
  return !(*this == other);
}

Category Category::CreateGroupTreeItem(unsigned numStages)
{
  Category result;
  foreach (QString name, _names)
    {
      if (!numStages)
        {
          break;
        }

      result << name;
      --numStages;
    }
  return result;
}

